# Copyright (c) 2008-2009 Mikhail Chernov 
#
# This file is part of dcExplorer.
#
# dcExplorer is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# dcExplorer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with dcExplorer.  If not, see <http://www.gnu.org/licenses/>.

package dcExplorer::wxui::widget::Map;
use strict;
use base 'Wx::ScrolledWindow';
use Wx;
use Wx qw(wxBG_STYLE_CUSTOM);
use Wx qw(wxMOUSE_BTN_LEFT wxMOUSE_BTN_RIGHT);
use Wx qw(WXK_LEFT WXK_RIGHT WXK_UP WXK_DOWN);
use Wx::Event qw(EVT_MOUSE_EVENTS EVT_KEY_DOWN);
use canvas::WX;
use Time::HiRes qw( usleep gettimeofday tv_interval );
use Switch;

sub new
{
	my $proto = shift;
	my $class = ref($proto) || $proto;
	my $parent = shift;
	my $id = shift;
	my $self = $class->SUPER::new($parent, $id, [-1, -1], [-1, -1]);
	$self->{Layers} = shift;
	$self->{sx} = shift || 500;
	$self->{sy} = shift || 500;
	$self->{bsize} = shift || 11;
	$self->ChangeView('Geo');
	$self->{bord_x} = 35;
	$self->{bord_y} = 15;
	$self->SetBackgroundStyle(wxBG_STYLE_CUSTOM);
	EVT_KEY_DOWN($self, sub {$_[0]->OnKeyPressed($_[1])});
	EVT_MOUSE_EVENTS($self, sub {$_[0]->OnMouseEvent($_[1])});
	return $self;
}

sub setLayers
{
	my $self = shift;
	$self->{Layers} = shift;
	$self->Refresh();
}

sub ChangeView
{
	my $self = shift;
	$self->{view} = shift;
}

sub OnDraw
{
	my $self = shift;
	my $start = [gettimeofday];
	my $dc = Wx::AutoBufferedPaintDC->new($self); 
	my ($dx, $dy) = $self->GetSizeWH;
	my ($x1, $y1) = ($self->{sx}, $self->{sy});
	my ($x2, $y2) = (int(($dx - $self->{bord_x}) / $self->{bsize}) + $x1, int(($dy - $self->{bord_y}) / $self->{bsize}) + $y1);
	my $canvas = dcExplorer::canvas::WX->new($dc, $x1, $y1, $x2, $y2, $self->{bsize}, $self->{bord_x}, $self->{bord_y});

	$_->display($canvas) foreach @{$self->{Layers}};

	my $interval = tv_interval($start, [gettimeofday]);
#	printf STDERR "OnDraw: %f seconds\n", $interval;
}

sub Move
{
	my $self = shift;
	my $dx = shift;
	my $dy = shift;
	return unless defined($dx) && defined($dy);
	$self->{sx} = ($self->{sx} + 1999 + $dx) % 2000 + 1;
	$self->{sy} = ($self->{sy} + 1999 + $dy) % 2000 + 1;
}

sub MoveTo
{
	my $self = shift;
	my $x = shift;
	my $y = shift;
	return unless defined($x) && defined($y);
	$self->{sx} = ($x + 1999) % 2000 + 1;
	$self->{sy} = ($y + 1999) % 2000 + 1;
}

sub ScaleUp
{
	my $self = shift;
	if ($self->{bsize} < 40)
	{
		$self->{bsize} += 2;
		return 1;
	}
}

sub ScaleDown
{
	my $self = shift;
	if ($self->{bsize} > 5)
	{
		$self->{bsize} -= 2;
		return 1;
	}
}

sub PixelToPlanet
{
	my $self = shift;
	my ($x, $y) = @_;
	$x = (int(($x - $self->{bord_x}) / $self->{bsize}) + $self->{sx} - 1) % 2000 + 1;
	$y = (int(($y - $self->{bord_y}) / $self->{bsize}) + $self->{sy} - 1) % 2000 + 1;
	return ($x, $y);
}

sub OnKeyPressed
{
	my $self = shift;
	my $event = shift;
#	printf "%s\n", $event->GetKeyCode;
	my $step = 5;
	switch ($event->GetKeyCode)
	{
		case ord('=')
			{ $self->Refresh if $self->ScaleUp }
		case ord('-')
			{ $self->Refresh if $self->ScaleDown }
		case WXK_RIGHT 
			{ $self->Move(+$step, 0); $self->Refresh }
		case WXK_LEFT 
			{ $self->Move(-$step, 0); $self->Refresh }
		case WXK_DOWN 
			{ $self->Move(0, +$step); $self->Refresh }
		case WXK_UP
			{ $self->Move(0, -$step); $self->Refresh }
#		case ord('S')
#			{ $self->ChangeView('Simple'); $self->Refresh}
#		case ord('P')
#			{ $self->ChangeView('Political'); $self->Refresh }
#		case ord('G')
#			{ $self->ChangeView('Geo'); $self->Refresh }
		else {$event->Skip}
	}
}

sub OnMouseEvent
{
	my $self = shift;
	my $event = shift;
	return unless defined $event;
	if ($event->ButtonDown(wxMOUSE_BTN_RIGHT))
	{
		($self->{px}, $self->{py}) = $self->PixelToPlanet($event->GetX, $event->GetY);
	}
	elsif ($event->ButtonUp(wxMOUSE_BTN_RIGHT))
	{
		($self->{px}, $self->{py}) = (undef, undef);
	}
	my $refresh = 0;
	if ($event->Dragging)
	{
		if (defined($self->{px}))
		{
			my ($ex, $ey) = $self->PixelToPlanet($event->GetX, $event->GetY);
			if ($ex != $self->{px} || $ey != $self->{py})
			{
				$self->Move($self->{px} - $ex, $self->{py} - $ey);
				$refresh = 1;
			}
		}
	}
	if (my $rotation = $event->GetWheelRotation())
	{
		my ($sx, $sy) = $self->PixelToPlanet($event->GetX, $event->GetY);
		if ($rotation < 0 && $self->ScaleDown || $rotation > 0 && $self->ScaleUp)
		{
			my ($ex, $ey) = $self->PixelToPlanet($event->GetX, $event->GetY);
			$self->Move($sx - $ex, $sy - $ey);
			$refresh = 1;
		}
	}
	$self->Refresh if $refresh;
	$event->ResumePropagation(3);
	$event->Skip;
}

1;
